﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CTThrottling.AlgorithmThrottling;

namespace CTThrottling
{
    public class LimitingFactory
    {
        /// <summary>
        /// 创建限流服务对象
        /// </summary>
        /// <param name="limitingType">限流模型</param>
        /// <param name="maxQps">最大QPS</param>
        /// <param name="limitSize">最大可用票据数</param>
        public static ILimitingService Build(LimitingType limitingType = LimitingType.TokenBucket, int maxQps = 100, int limitSize = 100)
        {
            switch (limitingType)
            {
                case LimitingType.TokenBucket:
                    return new TokenBucketLimitingService(maxQps, limitSize);                
                case LimitingType.LeakageBucket:
                    return new LeakageBucketLimitingService(maxQps, limitSize);
                default:
                    return new TokenBucketLimitingService(maxQps, limitSize);
            }
        }
    }

    /// <summary>
    /// 限流模式
    /// </summary>
    public enum LimitingType
    {
        TokenBucket,//令牌桶模式
        LeakageBucket//漏桶模式
    }

    public class LimitedQueue<T> : Queue<T>
    {
        private int _limit = 0;
        public const string QueueFulled = "TTP-StreamLimiting-1001";

        public int Limit
        {
            get => _limit;
            set => _limit = value;
        }

        /// <summary>
        /// 
        /// </summary>
        public LimitedQueue()
            : this(0)
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="limit"></param>
        public LimitedQueue(int limit)
            : base(limit)
        {
            this.Limit = limit;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public new bool Enqueue(T item)
        {
            if (_limit > 0 && this.Count >= this.Limit)
            {
                return false;
            }
            base.Enqueue(item);
            return true;
        }
    }
}
